package com.shareyi.simpleserver.core;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.shareyi.fileutil.FileUtil;
import com.shareyi.joywindow.server.HttpServer;
import com.shareyi.joywindow.server.exception.HttpServerException;
import com.shareyi.simpleserver.core.ServerConfig;
import com.shareyi.simpleserver.exception.SimpleServerException;
import com.shareyi.simpleserver.handler.HttpHandler;
import com.shareyi.simpleserver.servlet.WebApplication;


/**
 * This is a simple Http Server, it implements basic server  
 *@author David zhang
 *@since Tue 20 May 2011
 *@version 1.0
 */
public class SimpleHttpServer implements HttpServer{

private static Log log=LogFactory.getLog(SimpleHttpServer.class);
private  ServerConfig serverConfig;
private  int maxConn;
 private  boolean running=false;
 private static  SimpleHttpServer server; 
 private  ServerSocket serverSocket;
 private  ArrayList<Socket> sockets;
 private  WebApplication webApplication;
 /**
  * initial the local listening Server
 * @throws WoxException 
 * @throws SimpleServerException 
  */
 public  void init() throws HttpServerException {
	 
 //read server configuration
		File file=new File(FileUtil.getRunPath()+"/config/server.properties");
		serverConfig=ServerConfig.readServerConfig(file);
		HttpHandler.setAccess(serverConfig.getAccess());
		HttpHandler.setPostfixFilter(serverConfig.isPostfixFilter());
		HttpHandler.setPostfixs(serverConfig.getPostfixs());
		
		maxConn=serverConfig.getMaxConn();
	
		this.webApplication=new WebApplication();
		this.webApplication.init(serverConfig.getWebConfigPath());
		
		//read servlet config info
	//	ServletConfig servletCfg=ServletConfig.readServletConfig();
	//	ServletHandler.setServletConfig(servletCfg);
		
		//initial wox Struts
		//	WoxConfig.init(serverConfig.getWoxConfigPath());
		sockets=new ArrayList<Socket>(serverConfig.getMaxConn());
		running=true;
 }

 

 /**
  * start the local listening Server
  * @return start state
  */
 public  boolean start() throws  HttpServerException
 {
	 	try {
			serverSocket=new ServerSocket(serverConfig.getPort());
			new Thread() {
				   public void run() {
				    try {
				    //如果还在运行
				     while (running) {
				     final Socket socket;
				     if(sockets.size()<=maxConn)
				       {
				    	 socket = serverSocket.accept();
				    	 if(running)
				    	 {
				    		//启动处理
				    		addSocket(socket);
				    		new HttpHandler(socket).start();
				    	 }
				    	 else
				    		 socket.close();
				       }
				     else 
				    	 	Thread.sleep(800);
				     }
				    } catch (SocketException e) {
				    	
				    }catch(Exception ee)
				    {
				    	ee.printStackTrace();
				    }
				   }
				  }.start();
			} catch (IOException e) {
			return false;
		}	
	return true;
 }
 
 /**
  * stop local listening Server
  * @return stop state
  */
 
 public  boolean stop()
 {
	 //关闭所有连接
	 running=false;
	 synchronized (sockets) {
	 for (int i = 0; i < sockets.size(); i++) {
			Socket socket=sockets.get(i);
			if(!socket.isClosed())
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
	 
	 try {
		serverSocket.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
	log.info("SimpleHttpServer stoped!");
	return true;
 }
 
/**
 * get Single instance of SimpleHttpServer
 * @return SimpleHttpServer instance 
 */
 public static SimpleHttpServer getServerInstance()
 {
	 if(server==null)
	 {
		 server=new SimpleHttpServer();
	 }
	 return server;
 }
 
 
 /**
  * add socket to the socket List
  * @param socket
  */
 public  void addSocket(Socket socket)
 {
	 synchronized (sockets) {
		 sockets.add(socket);	
	}
 }

 
 /**
  * remove socket from the socket List
  * @param socket
  */
 public  void removeSocket(Socket socket)
 {
	 synchronized (sockets) {
		 sockets.remove(socket);	
	}
 }
 
 public  void startServer() throws HttpServerException {
	 
	 
  this.init();
  log.info("server starting:");
  log.info("base path:" + serverConfig.getBasePath());
  log.info("Listening at:" + serverConfig.getPort());
  
  if(!checkOtherRunning())		//如果无其它实例运行
   if(!this.start())
	   {
	   log.info("server start failed");
	   	throw new SimpleServerException("server start failed");
	   }
   log.info("server started succesfully");
 }

 public  boolean checkOtherRunning() throws SimpleServerException
 {
	 Socket socket=null;
	 PrintWriter writer=null;
	 BufferedReader reader=null;
	 
	 try {
		socket=new Socket("127.0.0.1", serverConfig.getPort());
		writer=new PrintWriter(socket.getOutputStream());
		reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
		writer.println("HEAD test_running.chk HTTP/1.1");
		writer.println();
		writer.flush();

		String res=reader.readLine();
		if("1000".equals(res))
		{
			return true;
		}else if("2000".equals(res))
		{
		  throw new SimpleServerException("服务器已启动，并且配置文件不允许多个实例运行");
		}else
			throw new SimpleServerException("查询其它运行的服务器失败，端口被其它程序占用！");
		
	 } catch (UnknownHostException e) {
		 	return false;
	 } catch (IOException e) {
		 return false;
	 } finally{
		 if(writer!=null)
		 {
			 try { writer.close();}catch (Exception e) {}
		 }
		 if(reader!=null)
			{
			 try { reader.close(); } catch (Exception e) {}
			}
		 if (socket!=null) {
			 try { socket.close(); } catch (Exception e) {}
		}
	 }
 }
 


public  String getBasePath() {
	return serverConfig.getBasePath();
}

public  String getIndex() {
	return serverConfig.getIndex();
}

public  int getPort() {
	return serverConfig.getPort();
}




public void setBindPath(String bindPath) {
	serverConfig.setBindPath(bindPath);
}


public  String getBindPath() {
	return serverConfig.getBindPath();
}


public  boolean isManyInstAllow()
{
	return serverConfig.isManyInstAllow(); 
}



public  WebApplication getWebApplication() {
	return webApplication;
}


}
